#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"

namespace nt_client
{
    class TcpClient
    {
    public:
        TcpClient(const std::string& ip, const uint16_t port)
            :server_ip_(ip), server_port_(port)
        {}

        ~TcpClient()
        {}

        // 初始化客户端
        void InitClient()
        {
            // 创建套接字
            sock_ = socket(AF_INET, SOCK_STREAM, 0);
            if (sock_ == -1)
            {
                std::cerr << "Create Socket Fail!" << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }

            std::cout << "Create Sock Succeess! " << sock_ << std::endl;
        }

        // 启动客户端
        void StartClient()
        {
            // 填充服务器的 sockaddr_in 结构体信息
            struct sockaddr_in server;
            socklen_t len = sizeof(server);
            memset(&server, 0, len);
            server.sin_family = AF_INET;
            inet_aton(server_ip_.c_str(), &server.sin_addr); // 将点分十进制转化为二进制IP地址的另一种方法
            server.sin_port = htons(server_port_);

            // 尝试重连 5 次
            int n = 5;
            while(n)
            {
                int ret = connect(sock_, (const struct sockaddr*)&server, len);

                if(ret == 0)
                {
                    // 连接成功，可以跳出循环
                    break;
                }

                // 尝试进行重连
                std::cerr << "网络异常，正在进行重连... 剩余连接次数: " << --n << std::endl;
                sleep(1);
            }

            // 如果剩余重连次数为 0，证明连接失败
            if(n == 0)
            {
                std::cerr << "连接失败! " << strerror(errno) << std::endl;
                close(sock_);
                exit(CONNECT_ERR);
            }

            // 连接成功
            std::cout << "连接成功!" << std::endl;

            // 进行业务处理
            Service();
        }

        // 业务处理
        void Service()
        {
            char buff[1024];
            std::string who = server_ip_ + "-" + std::to_string(server_port_);
            while(true)
            {
                // 由用户输入信息
                std::string msg;
                std::cout << "Please Enter >> ";
                std::getline(std::cin, msg);

                // 发送信息给服务器
                write(sock_, msg.c_str(), msg.size());

                // 接收来自服务器的信息
                ssize_t n = read(sock_, buff, sizeof(buff) - 1);
                if(n > 0)
                {
                    // 正常通信
                    buff[n] = '\0';
                    std::cout << "Client get: " << buff << " from " << who << std::endl;
                }
                else if(n == 0)
                {
                    // 读取到文件末尾（服务器关闭了）
                    std::cout << "Server " << who  << " quit!" << std::endl;
                    close(sock_); // 关闭文件描述符
                    break;
                }
                else
                {
                    // 读取异常
                    std::cerr << "Read Fail!" << strerror(errno) << std::endl;
                    close(sock_); // 关闭文件描述符
                    break;
                }
            }
        }
        
    private:
        int sock_; // 套接字
        std::string server_ip_; // 服务器IP
        uint16_t server_port_; // 服务器端口号
    };
}